#include "wm_lcd.h"

/**
  * @brief  Initializes the LCD according to the specified parameters
  *         in the LCD_InitTypeDef and create the associated handle.
  * @param  hlcd LCD handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_LCD_Init(LCD_HandleTypeDef *hlcd)
{
	uint32_t frame_cnt = 0, i = 0;
	
	if (hlcd == NULL)
	{
		return HAL_ERROR;
	}
	assert_param(IS_LCD_ALL_INSTANCE(hlcd->Instance));
	assert_param(IS_LCD_DRVSTR(hlcd->Init.HighDrive));
	assert_param(IS_LCD_BIAS(hlcd->Init.Bias));
	assert_param(IS_LCD_VOLTAGE(hlcd->Init.Volt));
	assert_param(IS_LCD_DUTY(hlcd->Init.Duty));
	
	if (hlcd->State == HAL_LCD_STATE_RESET)
	{
		hlcd->Lock = HAL_UNLOCKED;
		HAL_LCD_MspInit(hlcd);
	}
	hlcd->State = HAL_LCD_STATE_BUSY;
	
	WRITE_REG(hlcd->Instance->CR, (LCD_CR_PD | hlcd->Init.HighDrive | hlcd->Init.Bias | hlcd->Init.Volt | hlcd->Init.Duty));
	frame_cnt = 32768 / hlcd->Init.Freq / (hlcd->Init.Duty + 1);
	WRITE_REG(hlcd->Instance->FRQ, (frame_cnt & 0x7FF));
	for(i = 0; i < 8; i++)
	{
		WRITE_REG(hlcd->Instance->RAM[i], 0);
	}
	WRITE_REG(hlcd->Instance->COM_EN, 0);
	WRITE_REG(hlcd->Instance->SEG_EN, 0);
	
	WRITE_REG(hlcd->Instance->COM_EN, (hlcd->Init.ComEn & 0xFF));
	WRITE_REG(hlcd->Instance->SEG_EN, hlcd->Init.SegEn);
	
	SET_BIT(hlcd->Instance->CR, LCD_CR_EN);
	
	hlcd->State = HAL_LCD_STATE_READY;
	return HAL_OK;
}

/**
  * @brief  DeInitializes the LCD peripheral
  * @param  hlcd LCD handle
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_LCD_DeInit(LCD_HandleTypeDef *hlcd)
{
	if (hlcd == NULL)
	{
		return HAL_ERROR;
	}
	assert_param(IS_LCD_ALL_INSTANCE(hlcd->Instance));
	if (hlcd->State == HAL_LCD_STATE_BUSY)
	{
		return HAL_BUSY;
	}
	hlcd->State = HAL_LCD_STATE_BUSY;
	HAL_LCD_MspDeInit(hlcd);
	hlcd->Instance->CR = 0;
	hlcd->Instance->COM_EN = 0;
	hlcd->Instance->SEG_EN = 0;
	hlcd->State = HAL_LCD_STATE_RESET;
	__HAL_UNLOCK(hlcd);
	
	return HAL_OK;
}

/**
  * @brief  LCD MSP Init
  * @param  hlcd LCD handle
  * @retval None
  */
__attribute__((weak)) void HAL_LCD_MspInit(LCD_HandleTypeDef *hlcd)
{
	UNUSED(hlcd);
}

/**
  * @brief  LCD MSP DeInit
  * @param  hlcd LCD handle
  * @retval None
  */
__attribute__((weak)) void HAL_LCD_MspDeInit(LCD_HandleTypeDef *hlcd)
{
	UNUSED(hlcd);
}

/**
  * @brief  Writes a word in the specific LCD RAM.
  * @param  hlcd LCD handle
  * @param  RAMRegisterIndex specifies the LCD RAM Register.
  *   This parameter can be one of the following values:
  *     @arg LCD_RAM_REGISTER0: LCD RAM Register 0
  *     @arg LCD_RAM_REGISTER1: LCD RAM Register 1
  *     @arg LCD_RAM_REGISTER2: LCD RAM Register 2
  *     @arg LCD_RAM_REGISTER3: LCD RAM Register 3
  *     @arg LCD_RAM_REGISTER4: LCD RAM Register 4
  *     @arg LCD_RAM_REGISTER5: LCD RAM Register 5
  *     @arg LCD_RAM_REGISTER6: LCD RAM Register 6 
  *     @arg LCD_RAM_REGISTER7: LCD RAM Register 7  
  * @param  RAMRegisterMask specifies the LCD RAM Register Data Mask.
  * @param  Data specifies LCD Data Value to be written.
  * @retval None
  */
HAL_StatusTypeDef HAL_LCD_Write(LCD_HandleTypeDef *hlcd, uint32_t RAMRegisterIndex, uint32_t RAMRegisterMask, uint32_t Data)
{
	if (hlcd == NULL)
	{
		return HAL_ERROR;
	}
	
	if ((hlcd->State == HAL_LCD_STATE_READY) || (hlcd->State == HAL_LCD_STATE_BUSY))
	{
		assert_param(IS_LCD_RAM_REGISTER_INDEX(RAMRegisterIndex));
		
		__HAL_LOCK(hlcd);
		hlcd->State = HAL_LCD_STATE_BUSY;
		
		MODIFY_REG(hlcd->Instance->RAM[RAMRegisterIndex], ~(RAMRegisterMask), Data);
		hlcd->State = HAL_LCD_STATE_READY;
		__HAL_UNLOCK(hlcd);
		return HAL_OK;
	}
	else
	{
		return HAL_ERROR;
	}
}

/**
  * @brief Clears the LCD RAM registers.
  * @param hlcd: LCD handle
  * @retval None
  */
HAL_StatusTypeDef HAL_LCD_Clear(LCD_HandleTypeDef *hlcd)
{
	int i = 0;
	
	if ((hlcd->State == HAL_LCD_STATE_READY) || (hlcd->State == HAL_LCD_STATE_BUSY))
	{
		__HAL_LOCK(hlcd);
		hlcd->State = HAL_LCD_STATE_BUSY;
		
		for (i = 0; i < 8; i++)
		{
			hlcd->Instance->RAM[i] = 0;
		}
		hlcd->State = HAL_LCD_STATE_READY;
		__HAL_UNLOCK(hlcd);
		
		return HAL_OK;
	}
	else
	{
		return HAL_ERROR;
	}
}